Site Automation

Site creation, rebuild, and publishing are managed by this GNU Make makefile (Make Doc)

SHELL  := $(shell which bash)

# Copyright (C) 2017 George Clemmer

# Author: George Clemmer myglc2 at gmail dot com
# Keywords: emacs, github pages, orgmode, org-mode, bootstrap

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.  If not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

# Commentary:

# emacsite -- easy Emacs web sites

# Please also see README.org.

# emacsite uses GNU Make and GNU Emacs to automate the creation of web
# sites on GitHub.  Simple 'make' commands create a repo, build the
# site, and publish it to GitHub Pages.

# Make builds the site by running an Emacs server and using
# emacsclient to request HTML export of '.org' page source files.  'Org
# mode' markup in these files controls content display.  'ox-twbs.el',
# which uses the Bootstrap front-end framework to produce mobile first
# responsive sites, is used to export the pages to HTML.

# The server is started with 'make start'.  Subsequent 'make' commands
# may be issued using 'M-x shell make', 'M-x eshell make', or 'M-x
# compile' from within the Emacs server or from another emacs instance
# or from the command line.

# Source files may be edited using the Emacs server, another instance
# of emacs, or a different editor altogether.

# The site may be previewed locally with 'make preview'. A change may
# be committed with 'make commit', and published to GitHub with 'make
# gh'. Finally the emacs server may be killed with 'make stop'.

# Menus are generated by including into a page's source the
# 'header.org' file that contains the Emacs Lisp 'menu' code block
# that generates bootstrap menus.

# Emacs 'Font Lock' determines the colors and faces used to display
# code and 'ox-twbs.el' uses 'htmlize.el' to produce WYSIWYG export of
# such code to HTML.   However, when, as is typically the case, the
# Emacs server is run as a daemon or in batch mode, font lock is not
# active and code is exported in black and white.  To overcome this,
# Emacs is started with a GUI and switched to be a server.  This causes
# font lock to be active, produces WYSIWYG code export, and allows the
# appearance of exported code to be customized by loading an Emacs
# 'Custom Theme'

# The markup menu and sub-directory provide exemplar Org mode markup
# and bootstrap button automation.

# To increase reproducibility, 'ox-twbs.el' and 'htmlize.el' sources
# are provided and loaded.

REMOTE := github.com

# for debugging ...
# ... to print all $(warning ...)'s
#     DEBUG=1 make:
# ... to print the value of SYMBOL
#     make print-<SYMBOL>>
print-%:
        @echo $* = $($*)
        @echo $*\'s origin is $(origin $*)

# ignore default GNU suffixes
.SUFFIXES:

# select a browser
UNAME  := $(shell uname)
ifeq ($(UNAME),Linux)
BROWSER := $(firstword \
$(shell which chromium 2> /dev/null) \
$(shell which icecat 2> /dev/null) \
$(shell which conkeror 2> /dev/null)\
)
else ifeq ($(UNAME),Darwin)
BROWSER := open -a Google\ Chrome --args --allow-file-access-from-files
BROWSER := open -a Firefox.app
BROWSER := open -a Safari
endif
$(if $(DEBUG),$(warning BROWSER: $(BROWSER)),)

# determine URL, user and repo name from 'git remote origin'
GITHUB-URL := $(subst .git,,$(shell git config --get remote.origin.url))
$(if $(DEBUG),$(warning GITHUB-URL $(GITHUB-URL)),)
GITHUB-USR-REPO := $(subst git@github.com:,,$(GITHUB-URL))
$(if $(DEBUG),$(warning GITHUB-USR-REPO $(GITHUB-USR-REPO)),)
GITHUB-USR := $(firstword $(subst /, ,$(GITHUB-USR-REPO)))
$(if $(DEBUG),$(warning GITHUB-USR $(GITHUB-USR)),)
GITHUB-REPO := $(lastword $(subst /, ,$(GITHUB-USR-REPO)))
$(if $(DEBUG),$(warning GITHUB-REPO $(GITHUB-REPO)),)

# Org-mode page sources
# org files
ORGFILES := $(shell find . -maxdepth 3 -name "*.org")
$(if $(DEBUG),$(warning ORGFILES: $(ORGFILES)),)

# HTML page targets
HTMLxORG := $(addsuffix .html,$(basename $(ORGFILES)))
$(if $(DEBUG),$(warning HTMLxORG: $(HTMLxORG)),)

# make the site
.PHONY: all
all: pages
        echo To preview, open: $(PWD)/index.html

# preview the site locally
.PHONY: preview
preview: pages
        $(BROWSER) $(PWD)/index.html &

# export all .org files to .html
.PHONY: pages
pages: $(HTMLxORG)

# ensure we are on master
ONMASTER = if [ "$$(git rev-parse --abbrev-ref HEAD)" != "master" ]; then echo; echo "*** You are on '$$(git rev-parse --abbrev-ref HEAD)' branch" ; echo "*** Please check out 'master'" ; echo ; exit 1 ; fi

# is the working tree clean?
CLEAN = if [ -n "$$(git status --porcelain --untracked-files=no --short)" ]; then echo "Please 'make commit' or 'stash' your changes to:"; git status --short; exit 1 ; fi

# verify the server is not running and start it on home page
.PHONY: start
start:
        if ! emacsclient -s emacsite-server  --eval '(concat "The Server was Already Running")'; then emacs $(OPTIONS) --load=lisp/htmlize.el --load=lisp/ox-twbs.el --eval="(progn (setq org-confirm-babel-evaluate nil)(setq server-name \"emacsite-server\")(server-start)(find-file \"index.org\")(shell))"; fi;

# use emacsclient to export an .org file passing reldir ("$(@D)") in for use by header.org menu code.
%.html: %.org header.org
        $(ONMASTER)
        $(RM) -f $*.html $*.html*
        if ! emacsclient -s emacsite-server --eval '(progn (setq reldir "$(@D)") (set-buffer (find-file-noselect "$*.org")) (org-twbs-export-to-html) (concat "$*.org" " >>> " "$*.html"))'; then echo; printf "The Emacs server is not running \n"; printf "Please type 'make start'  \n"; echo; exit 1; fi

# stop the server
.PHONY: stop
stop:
        -emacsclient -s emacsite-server --eval '(kill-emacs)'

# emacsite include dependencies
about/gnumake.html: makefile
about/menus.html: header.org
./markup/code-markup.html: ./markup/code.org ./markup/code-buttons.org
./markup/code.html: ./markup/code-buttons.org
./markup/headlines-markup.html: ./markup/headlines.org ./markup/headlines-buttons.org
./markup/headlines.html: ./markup/headlines-buttons.org
./markup/images-markup.html: ./markup/images.org ./markup/images-buttons.org
./markup/images.html: ./markup/images-buttons.org
./markup/inline-markup.html: ./markup/inline.org ./markup/inline-buttons.org
./markup/inline.html: ./markup/inline-buttons.org
./markup/lists-markup.html: ./markup/lists.org ./markup/lists-buttons.org
./markup/lists.html: ./markup/lists-buttons.org
./markup/literal-markup.html: ./markup/literal.org ./markup/literal-buttons.org
./markup/literal.html: ./markup/literal-buttons.org
./markup/paragraphs-markup.html: ./markup/paragraphs.org ./markup/paragraphs-buttons.org
./markup/paragraphs.html: ./markup/paragraphs-buttons.org
./markup/tables-markup.html: ./markup/tables.org ./markup/tables-buttons.org
./markup/tables.html: ./markup/tables-buttons.org

# publish to GitHub
.PHONY: gh
gh:  .gh-update
        echo To view the site open: https://$(GITHUB-USR).github.io/$(GITHUB-REPO)/

# view on GitHub
.PHONY: view
view:  .gh-update
        $(BROWSER) https://$(GITHUB-USR).github.io/$(GITHUB-REPO)/

# commit changes
MESSAGE ?= $(shell bash -c 'read -s -p "Commit message: " pwd; echo $$pwd')
.PHONY: commit
commit:
        $(ONMASTER)
        git add . ; git commit -m "$(MESSAGE)"

# create a GitHub site repo
# use the current directory name for the reponame
NEWREPO := $(notdir $(CURDIR))
$(if $(DEBUG),$(warning NEWREPO: $(NEWREPO)),)
.PHONY: repo
repo:
        $(ONMASTER)
        $(CLEAN)
        # save upstream repo reference ...
        -git remote rename origin upstream
        # ... or, forget about it ...
        # -git remote remove origin
        bash -c 'read -s -p "Please enter your GitHub Username: " username; echo $$username > .username'
        curl -i -u $$(< .username) -d "{ \"name\": \"$(NEWREPO)\", \"homepage\": \"https://$$(< .username).github.io/$(NEWREPO)/\", \"private\": true}" https://api.github.com/user/repos
        git remote add origin -f git@$(REMOTE):$$(< .username)/$(NEWREPO).git
        git push origin -u master:master
        rm -f .username

# publish if pages are newer than the GitHub sentinel
.gh-update: $(HTMLxORG)
        $(ONMASTER)
        $(CLEAN)
        # push
        git push origin -u master:master
        # delete previous gh-pages branch
        # revision history for *.html
        -git branch -D gh-pages
        # make a new gh-pages branch
        git branch gh-pages
        git checkout gh-pages
        # check in the pages
        git add -f $(HTMLxORG)
        git commit -m "Github pages"
        # delete the old gh-pages branch
        -git push origin :gh-pages
        #  ... and push the new one
        git push -u origin gh-pages:gh-pages
        # rewind our local master branch keeping .html files
        git symbolic-ref HEAD refs/heads/master
        git rm --cached  $(HTMLxORG)
        touch .gh-update

# remove all pages
.PHONY: clean
clean:
        $(RM) -f $(HTMLxORG) *.html~